// "Copyright [2021] <Copyright Han>"

package cluster.networks;

import cluster.network_device.*;
import cluster.task_scheduler.TaskGenerator;
import cluster.network_controller.*;
import cluster.resource_scheduler.*;
import inet.node.inet.Router;
import inet.networklayer.configurator.ipv4;
import inet.networklayer.configurator.ipv4.*;


network PFCNetwork
{
    parameters:
        int numMachine = default(2);
        int numOxc = default(2);
        int numOpticalswitch8x64 = default(numMachine);  // Default it is the same as the machine num
        int numGpusperMachine = default(8);
        int switch_num = default(1);
        int numNvlink_port = default(4);
        int switch_delay = default(0);
        int inetModuleNumber = default(numGpusperMachine * numMachine);
        //int inetModuleNumber = 0;

    submodules:
        machine[numMachine] : Machine{
            parameters:
                numGpus = numGpusperMachine;
                numNvlink_port = numNvlink_port;
                my_index = index;
        }

        topo_manager : TopoManager {

        }

        networkcontroller: NetworkController {
            parameters:
                clustertype = 1; //ElectricalCluster
            gates:
                switch_port[switch_num];
                machine_port[numMachine];
        }  // Bug?????



        resourcescheduler: ResourceScheduler{
            parameters:
                numMachine = numMachine;
                numGpusperMachine = numGpusperMachine;
        }

         taskgenerator: TaskGenerator{
            parameters:
                maxnumGpus = numGpusperMachine * numMachine;
        }
        
        configurator: Ipv4NetworkConfiguratorPFC {
            parameters:
                @display("p=100,100;is=s");
                dumpAddresses = true;
                dumpTopology = true;
                dumpLinks = true;
                assignAddresses = false;
                inetModuleNum = inetModuleNumber;
                 addSubnetRoutes = false;
                optimizeRoutes = false;
                networkType = 1;
        }
        r[switch_num]: Router {
            parameters:
            enablePFC = true;
            enableECN = true;
            **.numPorts = numGpusperMachine*numMachine;
            **.pauseUnit = 10000;
        }
        adapter:controllerAdapter {
            parameters:
                numSwitch = switch_num;
        }

    connections allowunconnected:
        // Connect the data plane
        // Connect the machines first

         for i=0..numMachine-1, for j=0..numGpusperMachine-1 {
             machine[i].out_port[j] <-->Fiber<--> r[0].ethg++;
         }



        // Connect the networkcontroller - machine
        for i=0..numMachine-1 {
            networkcontroller.machine_port[i]<-->ControlPlane<-->machine[i].controller_port;
        }

        // Connect the switch - networkcontroller
        networkcontroller.adapter_port -->Fiber --> adapter.controller_port;

        // Connect apater and switch
        for i=0..switch_num-1{
            adapter.switch_port++ <--> ControlPlane <--> r[i].controlPort;
        }


        // Connect apater and configurator
        configurator.networkConfiguratorOutput  -->ControlPlane -->  adapter.configuration_port;
    
}
